//
// System.Runtime.Serialization.SerializationObjectManager.cs
//
// Author:
//   Robert Jordan (robertj@gmx.net)
//
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#ifndef SerializationObjectManager_h
#define SerializationObjectManager_h

// C# includes.
#include <Typedef.h>
#include <Defines.h>
#include <CSharpPropertyMethods.h>

// Riccsson includes.
#include <REvents.h>
#include <System/Collections/Hashtable.h>
#include <System/Runtime/Serialization/SerializationCallbacks.h>
#include <System/Collections/IHashCodeProvider.h>
#include <System/Collections/IComparer.h>

namespace Riccsson
{
    namespace System
    {
	    namespace Runtime
	    {
		    namespace Serialization
		    {
	            class SerializationObjectManager sealed
	            {
		            /*readonly*/ GC_PTR<StreamingContext> context;
		            /*readonly*/ GC_PTR<System::Collections::Hashtable> seen;

		            event<void, SerializationCallbacks::CallbackHandler> callbacks;

		            public: SerializationObjectManager (StreamingContext* context)
		            {
                        seen = new System::Collections::Hashtable (HashHelper::Instance, HashHelper::Instance);

			            this->context = context;
		            }
		
		            public: void RegisterObject (object* obj)
		            {
			            if (seen->Contains (obj))
				            return;

			            GC_PTR<SerializationCallbacks> sc = SerializationCallbacks::GetSerializationCallbacks (obj->GetType ());

			            seen [obj] = HashHelper::NonNullObject;
			            sc->RaiseOnSerializing (obj, context);

                        throw;
			            //if (sc->HasSerializedCallbacks) {
				        //    // record for later invocation
				        //    callbacks += delegate (StreamingContext* ctx)
				        //    {
					    //        sc.RaiseOnSerialized (obj, ctx);
				        //    };
			            //}
		            }

		            public: void RaiseOnSerializedEvent ()
		            {
			            if (callbacks != null)
				            callbacks (context);
		            }

		            class HashHelper : public System::Collections::IHashCodeProvider, public System::Collections::IComparer {
			            public: static GC_PTR<object> NonNullObject;
			            public: static GC_PTR<HashHelper> Instance;

			            private: HashHelper ()
			            {
			            }

                        STATIC(HashHelper)
						{
                            NonNullObject = new object ();
                            Instance = new HashHelper ();
						}

			            public: int GetHashCode (object* obj)
			            {
				            if (obj == null)
					            return 0;
				            return obj->GetHashCode();
			            }

			            public: int Compare (object* x, object* y)
			            {
				            return Object::ReferenceEquals (x, y) ? 0 : 1;
			            }
		            };
	            };
            }
		}
	}
}

#endif
